// Bison prologue
%{
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "Smtp.h"
#include "../NetTalk/DataBuffer.h"
#include "../ClientDispatch/ClientDispatchLog.h"

#define SMTP_COMMANDS_PARSER_DEBUG
	
#define YYSTYPE char*

/* typedef не мой, поэтому отступления от стиля BEGIN/END_STRUCT_DECLARATION */
#define YY_TYPEDEF_YY_BUFFER_STATE
typedef struct yy_buffer_state* YY_BUFFER_STATE;

#define YY_TYPEDEF_YY_SCANNER_T
typedef void* yyscan_t;
	
void yyerror(SmtpCommandHeaderPtr currentCommandHeader, const char *str)
{
	fprintf(stderr, "error: %s\n", str);
}
	
Boolean ParseDataFromClient(DataBuffer clientData, SmtpCommandHeaderPtr commandHeader)
{
	Boolean stringIsAccepted = NO;
	yyscan_t scanner;
	YY_BUFFER_STATE buffer;
	
	#ifdef SMTP_COMMANDS_PARSER_DEBUG
	Log("SmtpCommandsParser: In ParseDataFromClient()");
	Log("SmtpCommandsParser: clientData.data is at %p, commandHeader is %p", clientData.data, commandHeader);
	Log("SmtpCommandsParser: clientData.data is %s while length is %d", clientData.data, clientData.dataLength);
	#endif
	
	yylex_init(&scanner);
#ifdef SMTP_COMMANDS_PARSER_DEBUG
	Log("SmtpCommandsParser: scanner is %p", scanner);
#endif
	buffer = yy_scan_bytes(clientData.data, clientData.dataLength, scanner);
#ifdef SMTP_COMMANDS_PARSER_DEBUG
	Log("SmtpCommandsParser: buffer is %p", buffer);
#endif	
	// stringIsAccepted = yyparse(commandHeader);
	
	yy_delete_buffer(buffer, scanner);
	yylex_destroy(scanner);
	
	// return stringIsAccepted;
	return YES;
}
%}

%pure-parser
%parse-param {SmtpCommandHeaderPtr currentCommandHeader}
%parse-param {yyscan_t* scanner}
%lex-param {yyscan_t* scanner}

// Token definitions
%token SPACE CRLF COLON RIGHT_ANGLE_BRACKET LEFT_ANGLE_BRACKET AT
%token LOCAL_PART DOMAIN
%token CONTROL_COMMAND COMMAND_WITH_DOMAIN COMMAND_WITH_DATA COMMAND_WITH_ADDRESS

%start SmtpCommand

%%

// Grammar rules
SmtpCommand
:
COMMAND_WITH_ADDRESS COLON MailboxAddress
{
	free($1);
}
|
COMMAND_WITH_DOMAIN SPACE DOMAIN
{
	SmtpCommandWithDomainPtr commandWithDomain = 
		(SmtpCommandWithDomainPtr)calloc(1, sizeof(SmtpCommandWithDomain));
	
	currentCommandHeader = &(commandWithDomain->header);
	
	currentCommandHeader->type = Initiation;
	
	strncpy(commandWithDomain->domain, $3, MAX_DOMAIN_LENGTH);
	
	free($1);
	free($3);
}
|
CONTROL_COMMAND
{
	free($1);
}
;

MailboxAddress
:
LEFT_ANGLE_BRACKET LOCAL_PART AT DOMAIN RIGHT_ANGLE_BRACKET
{
	SmtpCommandWithAddressPtr commandWithAddress = 
		(SmtpCommandWithAddressPtr)calloc(1, sizeof(SmtpCommandWithAddress));
	
	currentCommandHeader = &(commandWithAddress->header);
	
	if (!strcmp($1, "MAIL FROM"))
		currentCommandHeader->type = MailTransactionStart;
	else if (!strcmp($1, "RCPT TO"))
		currentCommandHeader->type = RecipientInfo;
	
	sprintf($$, "%s@%s", $2, $4);
		
	strncpy(commandWithAddress->address.localPart, $2, MAX_USERNAME_LENGTH);
	strncpy(commandWithAddress->address.domain, $4, MAX_DOMAIN_LENGTH);	
}
;